local blaze = require "blaze"
local app = require "app"
local game = require "club.threecard.sudoku"
local gamelib = require "club.threecard.gamelib"
local Board = require "club.threecard.sudoku.ui.ingame.Board"
local CandidatesPanel = require "club.threecard.sudoku.ui.ingame.CandidatesPanel"
local PlayerState = require "club.threecard.sudoku.ui.ingame.PlayerState"

local const = game.util.const
local log = blaze.logging.get("InGameUI")

local M = game.ui.activity()

M.store_watchers = {
    ingame = {
        ["$"] = function(self, store, state, args, init)
            for _, player in pairs(state.players) do
                self:update_player_state(player)
            end
            self.mark_btn.gameObject:SetActive(not state.marking)
            self.unmark_btn.gameObject:SetActive(state.marking)
        end,
        ["清理"] = function(self, store, state, player)
            for _, player_state in ipairs(self.player_states) do
                player_state:hide()
            end
            self.ready_go_fx:SetActive(false)
        end,
        ["玩家进入"] = function(self, store, state, player)
            local player_state = self:update_player_state(player)
            player_state:show_enter()
        end,
        ["玩家离开"] = function(self, store, state, player)
            local player_state = self:update_player_state(player)
            player_state:show_leave()
        end,
        ["谜题进度变更"] = function(self, store, state, player)
            self:update_player_state(player)
        end,
        ["游戏阶段变更"] = function(self, store, state, args)
            if state.phase_id == 1 then
                -- 准备阶段
                self:play_ready_go()
                self.board:hide_cells()
            elseif state.phase_id == 2 then
                -- 进入解谜阶段
                self.board:show_cells()
            end
        end,
        ["笔记状态变更"] = function(self, store, state, args)
            self.mark_btn.gameObject:SetActive(not state.marking)
            self.unmark_btn.gameObject:SetActive(state.marking)
        end
    }
}

function M:ctor()
    self.res = "club.threecard.sudoku/ui/ingame.b:InGameUI"
    self.last_size = nil
    self.board = nil
    self.candidates_panel = nil
    self.player_states = {
        PlayerState.new(),
        PlayerState.new()
    }
end

function M:on_load()
    self:super("on_load")
    for _, player_state in ipairs(self.player_states) do
        player_state:load()
    end
end

function M:on_injected(bind)
    bind("button.click", self.erase_btn, self.on_erase)
    bind("button.click", self.undo_btn, self.on_undo)
    bind("button.click", self.mark_btn, self.on_mark)
    bind("button.click", self.unmark_btn, self.on_unmark)
    bind("button.click", self.hint_btn, self.on_hint)
    bind("button.click", self.exit_btn, self.on_exit)
    bind("shortcut.escape", self.exit_btn.gameObject, self.on_exit)
    self.board:set_parent(self.board_root)

    for i=1, #self.player_states do
        local player_state = self.player_states[i]
        player_state:hide()
        local obj = self.player_states_root:Find(tostring(i)).gameObject
        player_state:set_gameobject(obj, true)
    end
    self.time_txt.text = ""
    local function loop()
        local ingame = game.store.ingame
        while true do
            game.coroutine.wait(1)
            local phase_id = ingame.state.phase_id
            if phase_id == const.PHASE_SOLVE_ID then
                self.time_txt.text = game.i18n.time(ingame.state.game_elapsed, "elapsed1")
            end
        end
    end
    self.co = game.coroutine.start(loop)
end

function M:after_route_enter(to, from)
    local _, roomconfig = game.roomcache.get(gamelib.game_scene.room_config_id)
    if roomconfig.mode == "火拼" then
        game.audio.post("speed-race")
    end

    if self.last_size == roomconfig.size then
        self:super("after_route_enter", to, from)
        return
    end

    if self.last_size ~= nil then
        self.board:release()
        self.candidates_panel:release()
    end

    self.board = Board.new(roomconfig.size)
    self.board:load()
    if self.loaded then
        self.board:set_parent(self.board_root)
    end
    self.candidates_panel = CandidatesPanel.new(self, roomconfig.size)

    self:super("after_route_enter", to, from)
    self.candidates_panel:set_gameobject(self.candidates_panel_obj, true)
    self.last_size = roomconfig.size
    self.time_txt.text = ""
end

function M:update_player_state(player)
    local player_state = self.player_states[player.seat.no]
    if not player_state then
        log.warn(string.format("错误的座位号：%s", blaze.dump(player, 5)))
        return
    end
    player_state:show()
    player_state:set_player(player)
    if player.total_cells <= 0 then
        player_state:set_progress(0)
    else
        player_state:set_progress(player.solved_cells / player.total_cells)
    end
    player_state:set_hearts(player.max_miss - player.missed, player.max_miss)
    player_state:set_puzzles(player.solved_puzzles, player.total_puzzles)
    return player_state
end

function M:play_ready_go()
    self.ready_go_fx:SetActive(false)
    self.ready_go_fx:SetActive(true)
end

function M:on_erase()
    game.store.ingame.erase()
end

function M:on_undo()
    game.store.ingame.undo()
end

function M:on_mark()
    game.store.ingame.set_marking(true)
end

function M:on_unmark()
    game.store.ingame.set_marking(false)
end

function M:on_hint()
    game.store.ingame.hint()
end

function M:on_exit()
    game.audio.post("click")
    if game.store.ingame.state.can_leave_game then
        game.game_scene.leave()
    else
        app.msgbox.show({
            content = game.i18n.text("sudoku:leave game alert"),
            on_confirm = game.game_scene.leave,
            cancelable = true,
        })
    end
end

function M:on_candidate_click(value)
    local ingame = game.store.ingame
    local state = ingame.state
    local cell = state.selected_cell
    if not cell then
        return
    end

    if state.marking then
        ingame.toggle_mark({
            x = cell.x,
            y = cell.y,
            value = value
        })
    else
        ingame.solve({
            x = cell.x,
            y = cell.y,
            value = value
        })
    end
end

function M:on_release()
    if self.co then
        game.coroutine.stop(self.co)
        self.co = nil
    end
end

return M